﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MobileSales.Model.Products;
using System.Text;
using MobileSales.Common.Logger;
using MobileSales.Model.Params;
using MobileSales.Website.EmployeeService;
using MobileSales.Model.Employees;
using MobileSales.Website.Properties;
using MobileSales.Model.Orders;
using MobileSales.Website.OrderService;
using MobileSales.Website.ClientService;
using MobileSales.Website.Localization;
using MobileSales.Model.Tasks;
using MobileSales.Website.TaskService;
using MobileSales.Model.Documents;
using MobileSales.Website.DocumentService;
using System.Threading;
using System.Globalization;

namespace MobileSales.Website.Infrastructure
{
    public static class HtmlHelperExtensions
    {
        #region Token
        private static String Token(HtmlHelper helper)
        {
            return (String)helper.ViewContext.ViewData[MobileSales.Website.Controllers.ControllerBase.TokenKey];
        } 
        #endregion

        #region CategoryTree
        public static MvcHtmlString CategoryTree(this HtmlHelper helper, Category rootCategory, string controllerName)
        {
            if (rootCategory == null)
            {
                return MvcHtmlString.Empty;
            }

            TagBuilder li = new TagBuilder("li");
            //TagBuilder span = new TagBuilder("span");
            //span.MergeAttribute("class", "folder");

            /* details link */
            TagBuilder a = new TagBuilder("a");
            a.MergeAttribute("href", string.Format("/{0}/Details/{1}", controllerName, rootCategory.Id));
            a.InnerHtml = rootCategory.Name;
            li.InnerHtml += a.ToString();
            li.InnerHtml += Environment.NewLine;

            /* edit */
            a = new TagBuilder("a");
            a.MergeAttribute("href", string.Format("/{0}/Edit/{1}", controllerName, rootCategory.Id));
            a.InnerHtml += String.Format("<img src=\"/Content/images/icons/edit.gif\" alt=\"{0}\" title=\"{0}\"/>",Strings.Edit);
            li.InnerHtml += a.ToString();
            li.InnerHtml += Environment.NewLine;

            /* remove */
            a = new TagBuilder("a");
            a.MergeAttribute("href", string.Format("/{0}/Delete/{1}", controllerName, rootCategory.Id));
            a.InnerHtml += String.Format("<img src=\"/Content/images/icons/delete.gif\" alt=\"{0}\" title=\"{0}\"/>",Strings.Delete);
            li.InnerHtml += a.ToString();
            li.InnerHtml += Environment.NewLine;

            //li.InnerHtml += span.ToString();

            /* children */
            if (rootCategory.Children != null)
            {
                if (rootCategory.Children.Count > 0)
                {
                    TagBuilder ul = new TagBuilder("ul");
                    foreach (var child in rootCategory.Children)
                    {
                        ul.InnerHtml += CategoryTree(helper, child, controllerName).ToString();
                        ul.InnerHtml += Environment.NewLine;
                    }
                    li.InnerHtml += ul.ToString();
                    li.InnerHtml += Environment.NewLine;
                }
            }

            return MvcHtmlString.Create(li.ToString());
        } 
        #endregion

        #region CategorySelect
        
        public static MvcHtmlString CategorySelect(this HtmlHelper helper, string fieldname, 
            bool multipleSelect = false, int[] selectedValues = null, string topLevelLabel = null)
        {
            if (topLevelLabel != null) topLevelLabel = Strings.TopLevelCategory;
            if (selectedValues != null && selectedValues.Count() == 0) selectedValues = null;

            IEnumerable<Category> categories = null;
            try
            {
                ProductService.ProductServiceClient productService = new ProductService.ProductServiceClient();
                productService.AddValidationToken(Token(helper));
                categories = productService.GetCategoryTree();
                productService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("size", "10");
            select.MergeAttribute("name", fieldname);
            if (multipleSelect)
            {
                select.MergeAttribute("multiple", "multiple");
            }
                
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("<option value=\"\"{0}>{1}</option>", selectedValues != null ? "" : " selected", Strings.TopLevelCategory);

            foreach (var category in categories)
            {
                sb.Append(GetCategory(category,selectedValues));
            }

            select.InnerHtml = sb.ToString();

            return MvcHtmlString.Create(select.ToString());
        }

        private static string GetCategory(Category root, int[] selectedIds, int level = 0)
        {
            StringBuilder sb = new StringBuilder();

            TagBuilder option = new TagBuilder("option");
            option.MergeAttribute("value", root.Id.ToString());
            if (selectedIds != null && selectedIds.Contains(root.Id))
            {
                option.MergeAttribute("selected", "selected");
            }
            string spaces = new StringBuilder().Insert(0, "&nbsp;", level * 3).ToString();
            option.InnerHtml = spaces + root.Name;

            sb.Append(option.ToString());

            if (root.Children != null && root.Children.Count > 0)
            {
                foreach (var child in root.Children)
                {
                    sb.Append(GetCategory(child, selectedIds, level + 1));
                }
            }

            return sb.ToString();
        } 
        #endregion

        #region ParamTypeSelect
        public static MvcHtmlString ParamTypeSelect(this HtmlHelper helper, string fieldName, ParamType? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            ParamType[] paramTypes = (ParamType[])Enum.GetValues(typeof(ParamType));
            if (paramTypes != null)
            {
                foreach (var type in paramTypes)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", type.ToString());
                    if (selectedValue.HasValue && type.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = type.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());
        } 
        #endregion

        #region FieldTypeSelect
        public static MvcHtmlString FieldTypeSelect(this HtmlHelper helper, string fieldName, FieldType? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            FieldType[] fieldTypeValues = (FieldType[])Enum.GetValues(typeof(FieldType));
            if (fieldTypeValues != null)
            {
                foreach(var fieldTypeVal in fieldTypeValues)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", fieldTypeVal.ToString());
                    if (selectedValue.HasValue && fieldTypeVal.Equals(selectedValue))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = fieldTypeVal.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());
        }
        #endregion

        #region ParamInputLabel
        public static MvcHtmlString ParamInputLabel(this HtmlHelper helper, Param param)
        {
            TagBuilder label = new TagBuilder("label");
            label.MergeAttribute("for", param.Name);
            label.InnerHtml = param.DisplayName;
            return MvcHtmlString.Create(label.ToString());
        }
        #endregion

        #region ParamInput
        public static MvcHtmlString ParamInput(this HtmlHelper helper, Param param, string value = null)
        {
            switch(param.FieldType) 
            {
                case FieldType.Boolean:
                    return CheckboxInput(param, value);
                case FieldType.Dictionary:
                    return SelectInput(param, value);
                default:
                    return TextInput(param, value);
            }
        } 

        #region CheckboxInput
        public static MvcHtmlString CheckboxInput(Param param, string value = null) 
        {
            TagBuilder input = new TagBuilder("input");
            input.MergeAttribute("type", "checkbox");
            input.MergeAttribute("name", param.Name);                
            bool isChecked = false;
            if (value != null)
            {
                isChecked = bool.Parse(value);
            }
            else if (param.DefaultValue!=null)
            {
                isChecked = bool.Parse(param.DefaultValue);
            }
            if (isChecked)
                input.MergeAttribute("checked", "checked");

            if (param.IsReadOnly && value != null)
            {
                input.MergeAttribute("disabled", "disabled");
            }
            return MvcHtmlString.Create(input.ToString());
        } 
	    #endregion

        #region TextInput
        public static MvcHtmlString TextInput(Param param, string value = null)
        {
            String validationString = "";
            TagBuilder input = new TagBuilder("input");
            input.MergeAttribute("type", "text");
            if (param.FieldType == FieldType.DateTime)
                input.AddCssClass("datepicker");

            input.MergeAttribute("name", param.Name);
            input.MergeAttribute("id", param.Name);
            bool isNumeric = (param.FieldType == FieldType.Integer || param.FieldType == FieldType.Double);

            if (isNumeric || param.IsRequired)
            {
                input.MergeAttribute("data-val", "true");
                validationString = String.Format("&nbsp;<span class=\"field-validation-valid\" data-valmsg-for=\"{0}\" data-valmsg-replace=\"true\"></span>", param.Name);
            }

            if (value != null)
            {
                input.MergeAttribute("value", value);
            }
            else if (value == null && param.DefaultValue != null)
            {
                input.MergeAttribute("value", param.DefaultValue);
            }
            
            if (param.IsReadOnly && value != null)
            {
                input.MergeAttribute("disabled", "disabled");
            }

            if (param.MaxLength.HasValue && param.FieldType == FieldType.String)
            {
                input.MergeAttribute("maxlength", param.MaxLength.Value.ToString());
            }
            if (param.IsRequired)
            {
                input.MergeAttribute("data-val-required", String.Format(ErrorStrings.ThisFieldIsRequired, param.DisplayName));
            }
            if (isNumeric)
            {
                input.MergeAttribute("data-val-number", String.Format(ErrorStrings.ThisFieldIsNumeric, param.DisplayName));
            }
            return MvcHtmlString.Create(input.ToString() + validationString);
        } 
        #endregion

        #region SelectInput
        public static MvcHtmlString SelectInput(Param param, string selectedValue = null)
        {
            TagBuilder input = new TagBuilder("select");
            input.MergeAttribute("name", param.Name);
            DictionaryParam dict = (DictionaryParam)param.GetValue(param.DefaultValue);

            if (!param.IsRequired)
            {
                TagBuilder option = new TagBuilder("option");
                option.MergeAttribute("value", "");
                if (selectedValue == null)
                    option.MergeAttribute("selected", "selected");
                option.InnerHtml = "none";
                input.InnerHtml += option.ToString();
            }

            foreach (var k in dict.Keys)
            {
                TagBuilder option = new TagBuilder("option");
                option.MergeAttribute("value", dict[k]);
                if (selectedValue != null && dict[k].Equals(selectedValue))
                {
                    option.MergeAttribute("selected", "selected");
                }
                option.InnerHtml = k;
                input.InnerHtml += option.ToString();
            }

            if (param.IsReadOnly && selectedValue != null)
            {
                input.MergeAttribute("disabled", "disabled");
            }
            return MvcHtmlString.Create(input.ToString());
        }
        #endregion

        #endregion

        #region ParamsFor
        public static MvcHtmlString ParamsFor(this HtmlHelper helper, ParamType paramType, IDictionary<Param, string> values)
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                ParamService.ParamServiceClient paramService = new ParamService.ParamServiceClient();
                paramService.AddValidationToken(Token(helper));
                IEnumerable<Param> parameters = paramService.GetParamListByType(paramType);
                paramService.Close();
                foreach (var p in parameters)
                {
                    sb.AppendFormat("<div class=\"display-label\">{0}</div>", ParamInputLabel(helper, p));
                    string val = (values != null)
                                ? values.Where(x => x.Key.Id.Equals(p.Id)).Select(x => x.Value.ToString()).FirstOrDefault()
                                : null;
                    if (val == null)
                    {
                        if (p.FieldType != FieldType.Dictionary)
                            val = p.DefaultValue;
                        else if (p.IsRequired)
                        {
                            String[] kv = p.DefaultValue.Split(';');
                            if (kv.Length > 0)
                            {
                                kv = kv[0].Split('=');
                                if (kv.Length == 2)
                                    val = kv[1];
                            }
                        }
                    }
                    if (val!=null && p.FieldType == FieldType.Boolean)
                        val = Boolean.Parse(val) ? Strings.Yes : Strings.No;
                    sb.AppendFormat("<div class=\"display-field\">{0}</div>", val);
                }
                return MvcHtmlString.Create(sb.ToString());
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }
        }
        #endregion

        #region ParamsEditorsFor
        public static MvcHtmlString ParamsEditorsFor(this HtmlHelper helper, ParamType paramType, IDictionary<Param, string> values = null)
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                ParamService.ParamServiceClient paramService = new ParamService.ParamServiceClient();
                paramService.AddValidationToken(Token(helper));
                IEnumerable<Param> parameters = paramService.GetParamListByType(paramType);
                paramService.Close();
                foreach (var p in parameters)
                {
                    sb.AppendFormat("<div class=\"editor-label\">{0}</div>", ParamInputLabel(helper, p));
                    string val = (values != null)
                                ? values.Where(x => x.Key.Id.Equals(p.Id)).Select(x => x.Value.ToString()).FirstOrDefault()
                                : null;
                    sb.AppendFormat("<div class=\"editor-field\">{0}</div>", ParamInput(helper, p, val));
                }
                return MvcHtmlString.Create(sb.ToString());
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }
        } 
        #endregion

        #region TaxSelect
        public static MvcHtmlString TaxSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<Tax> taxes = null;
            try
            {
                ProductService.ProductServiceClient productService = new ProductService.ProductServiceClient();
                productService.AddValidationToken(Token(helper));
                taxes = productService.GetTaxList();
                productService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (taxes != null)
            {
                foreach (var tax in taxes)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", tax.Id.ToString());
                    if (selectedValue.HasValue && tax.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = PercentageFormat(null,tax.Value).ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());
        }
        #endregion

        #region UnitSelect
        public static MvcHtmlString UnitSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<Unit> units = null;
            try
            {
                ProductService.ProductServiceClient productService = new ProductService.ProductServiceClient();
                productService.AddValidationToken(Token(helper));
                units = productService.GetUnitList();
                productService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (units != null)
            {
                foreach (var tax in units)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", tax.Id.ToString());
                    if (selectedValue.HasValue && tax.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = tax.Name.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());
        }
        #endregion

        #region ContractSelect
        public static MvcHtmlString ContractSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<Contract> contracts = null;
            try
            {
                EmployeeServiceClient employeeService = new EmployeeServiceClient();
                employeeService.AddValidationToken(Token(helper));
                contracts = employeeService.GetContractList();
                employeeService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (contracts != null)
            {
                foreach (var contract in contracts)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", contract.Id.ToString());
                    if (selectedValue.HasValue && contract.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = contract.Name.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());
        } 
        #endregion

        #region RoleSelect
        public static MvcHtmlString RoleSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<Role> roles = null;
            try
            {
                EmployeeServiceClient employeeService = new EmployeeServiceClient();
                employeeService.AddValidationToken(Token(helper));
                roles = employeeService.GetRoleList();
                employeeService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (roles != null)
            {
                foreach (var role in roles)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", role.Id.ToString());
                    if (selectedValue.HasValue && role.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = role.Name.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());

        } 
        #endregion

        #region EmployeeSelect
        public static MvcHtmlString EmployeeSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null, bool nullable = true)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);

            if (nullable)
            {
                TagBuilder option = new TagBuilder("option");
                option.MergeAttribute("value", "");
                option.InnerHtml = Strings.NoneCategory;
                if (!selectedValue.HasValue)
                {
                    option.MergeAttribute("selected", "selected");
                }
                select.InnerHtml += option.ToString();
            }

            IDictionary<string, int> employees = null;
            try
            {
                EmployeeServiceClient employeeService = new EmployeeServiceClient();
                employeeService.AddValidationToken(Token(helper));
                employees = employeeService.GetEmployeeLoginList();
                employeeService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (employees != null)
            {
                foreach (var employeeLogin in employees.Keys)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", employees[employeeLogin].ToString());
                    if (selectedValue.HasValue && employees[employeeLogin].Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = employeeLogin.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());

        }
        #endregion

        #region MessageCount
        public static MvcHtmlString MessageCount(this HtmlHelper helper, int employeeId)
        {
            if (employeeId == 0)
                return MvcHtmlString.Empty;

            EmployeeServiceClient employeeService = new EmployeeServiceClient();
            employeeService.AddValidationToken(Token(helper));
            try
            {
                int messageAmount = employeeService.CountNewMessages(employeeId);
                return MvcHtmlString.Create(string.Format("<a href=\"{0}\">{2} ({1})</a>", "/Messages", messageAmount, Strings.Messages));
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
            }
            employeeService.Close();
            return MvcHtmlString.Empty;
        } 
        #endregion

        #region ClientSelect
        public static MvcHtmlString ClientSelect(this HtmlHelper helper, string fieldname,
        bool multipleSelect = false, int[] selectedValues = null, bool nullable = false)
        {
            if (selectedValues != null && selectedValues.Count() == 0) selectedValues = null;

            IDictionary<int, string> clients = null;
            try
            {
                ClientService.ClientServiceClient clientService = new ClientService.ClientServiceClient();
                clientService.AddValidationToken(Token(helper));
                clients = clientService.GetClientNameList();
                clientService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldname);
            if (multipleSelect)
            {
                select.MergeAttribute("size", "10");
                select.MergeAttribute("multiple", "multiple");
            }

            StringBuilder sb = new StringBuilder();
            if (nullable)
            {
                sb.AppendFormat("<option value=\"\"{0}>{1}</option>", selectedValues != null ? "" : " selected", Strings.NoneCategory);
            }

            foreach (var clientId in clients.Keys)
            {
                TagBuilder option = new TagBuilder("option");
                option.MergeAttribute("value", clientId.ToString());
                option.InnerHtml = clients[clientId];
                if (selectedValues != null && selectedValues.Contains(clientId))
                    option.MergeAttribute("selected", "selected");
                sb.Append(option.ToString());
            }

            select.InnerHtml = sb.ToString();

            return MvcHtmlString.Create(select.ToString());
        } 
        #endregion

        #region ClientGroupSelect
        public static MvcHtmlString ClientGroupSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);

            TagBuilder option = new TagBuilder("option");
            option.MergeAttribute("value", "");
            if (!selectedValue.HasValue)
            {
                option.MergeAttribute("selected", "selected");
            }
            select.InnerHtml += option.ToString();

            IEnumerable<Model.Clients.ClientGroup> groups = null;
            try
            {
                ClientService.ClientServiceClient clientService = new ClientService.ClientServiceClient();
                clientService.AddValidationToken(Token(helper));
                groups = clientService.GetClientGroupList();
                clientService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            foreach (var group in groups)
            {
                option = new TagBuilder("option");
                option.MergeAttribute("value", group.Id.ToString());
                if (selectedValue.HasValue && selectedValue.Value.Equals(group.Id))
                {
                    option.MergeAttribute("selected", "selected");
                }
                option.InnerHtml = group.Name;
                select.InnerHtml += option.ToString();
            }

            return MvcHtmlString.Create(select.ToString());
        } 
        #endregion

        #region OrderStatusSelect
        public static MvcHtmlString OrderStatusSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<OrderStatus> statuses = null;
            try
            {
                OrderServiceClient orderService = new OrderServiceClient();
                orderService.AddValidationToken(Token(helper));
                statuses = orderService.GetOrderStatusList();
                orderService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (statuses != null)
            {
                foreach (var status in statuses)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", status.Id.ToString());
                    if (selectedValue.HasValue && status.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = status.Name.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());

        }  
        #endregion

        #region PriceCount
        public static double PriceCount(this HtmlHelper helper, double basePrice, double tax, double spread = 0.0, double quantity = 1)
        {
            return (1 + tax) * (basePrice * (1 + spread)) * quantity;
        } 
        #endregion

        #region TotalValueCount
        public static double TotalValueCount(this HtmlHelper helper, IEnumerable<OrderItem> items)
        {
            double result = 0;
            foreach (var item in items)
            {
                result += PriceCount(helper, item.Product.Price, item.Product.Tax.Value, item.Product.Spread, item.Quantity);
            }
            return result;
        } 
        #endregion

        #region ClientIdentity
        public static MvcHtmlString ClientIdentity(this HtmlHelper helper, int clientId)
        {
            ClientServiceClient cli = new ClientServiceClient();
            cli.AddValidationToken(Token(helper));
            MobileSales.Model.Clients.Client client = cli.GetClient(clientId);
            if (client != null)
            {
                String identity = String.Format("{0}<br />{1}<br />{2}<br />{3}, {4}<br />NIP: {5}", client.Name,
                                        client.Name2, client.Street, client.Zipcode, client.City, client.Nip);
                return MvcHtmlString.Create(identity);
            }
            return MvcHtmlString.Empty;
        } 
        #endregion

        #region EmployeeIdentity
        public static MvcHtmlString EmployeeIdentity(this HtmlHelper helper, int employeeId)
        {
            EmployeeServiceClient cli = new EmployeeServiceClient();
            cli.AddValidationToken(Token(helper));
            MobileSales.Model.Employees.Employee employee = cli.GetEmployee(employeeId);
            if (employee != null)
            {
                String identity = String.Format("{0}<br />{1}<br />{2}<br />{3}, {4}<br />Login: {5}", employee.Firstname,
                                        employee.Lastname, employee.Street, employee.Zipcode, employee.City, employee.Login);
                return MvcHtmlString.Create(identity);
            }
            return MvcHtmlString.Empty;
        }
        #endregion

        #region EmployeeFullName
        public static MvcHtmlString EmployeeFullName(this HtmlHelper helper, int employeeId)
        {
            EmployeeServiceClient cli = new EmployeeServiceClient();
            cli.AddValidationToken(Token(helper));
            MobileSales.Model.Employees.Employee employee = cli.GetEmployee(employeeId);
            if (employee != null)
            {
                String identity = String.Format("{0} {1}", employee.Lastname, employee.Firstname);
                return MvcHtmlString.Create(identity);
            }
            return MvcHtmlString.Empty;
        }
        #endregion

        #region ProductSelect
        public static MvcHtmlString ProductSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<Product> products = null;
            try
            {
                ProductService.ProductServiceClient productService = new ProductService.ProductServiceClient();
                productService.AddValidationToken(Token(helper));
                products = productService.GetProductList();
                productService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (products != null)
            {
                foreach (var product in products)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", product.Id.ToString());
                    if (selectedValue.HasValue && product.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = product.Name.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());
        }
        #endregion

        #region ScheduleCalendar
        public static MvcHtmlString ScheduleCalendar(this HtmlHelper helper, int employeeId, IEnumerable<MobileSales.Model.Tasks.Schedule> schedules,
            int year = -1, int month = -1)
        {
            if (year < 0 || month < 0)
            {
                year = DateTime.Now.Year;
                month = DateTime.Now.Month;
            }

            DateTime firstDay = new DateTime(year, month, 1);
            int daysInCurrentMonth = DateTime.DaysInMonth(firstDay.Year, firstDay.Month);
            DateTime lastDay = new DateTime(year, month, daysInCurrentMonth);
            // Sunday casted to int gives 0 but that will not work for us, we need 7 to be able to calculate number of empty cells correctly
            int dayOfWeekFirst = ((int)firstDay.DayOfWeek > 0) ? (int)firstDay.DayOfWeek : 7;
            int dayOfWeekLast = ((int)lastDay.DayOfWeek > 0) ? (int)lastDay.DayOfWeek : 7;
            dayOfWeekLast = 7 - dayOfWeekLast;

            String[] dayNames = new String[] { Strings.Mon, Strings.Tue, Strings.Wed, Strings.Thu, Strings.Fri, Strings.Sat, Strings.Sun };
            String[] monthNames = new String[] { Strings.January, Strings.February, Strings.March, Strings.April, Strings.May, Strings.June, 
                                                 Strings.July, Strings.August, Strings.September, Strings.October, Strings.November, Strings.December };



            String prev = String.Format("<a href=\"{0}?employeeId={1}&date={2}\">&laquo;</a>", 
                                        "/Schedules/", 
                                        employeeId,
                                        firstDay.AddMonths(-1).ToShortDateString());

            String next = String.Format("<a href=\"{0}?employeeId={1}&date={2}\">&nbsp;&raquo;&nbsp;</a>",
                                        "/Schedules/",
                                        employeeId,
                                        firstDay.AddMonths(1).ToShortDateString());



            TagBuilder table = new TagBuilder("table");
            table.MergeAttribute("class", "calendar-table");
            table.AddCssClass("calendar");
            table.InnerHtml = "<thead>" +
                              "      <tr>" +
                              "         <th>" + prev + "</th>" +
                              "         <th colspan=\"5\">" + String.Format("{0} {1}", monthNames[month-1], year) + "</th>" +
                              "         <th>" + next + "</th>" +
                              "      </tr>" +
                              "</thead>";

            String dayNamesHtml = "";
            foreach (var dayName in dayNames)
            {
                dayNamesHtml += String.Format("<td>{0}</td>", dayName);
            }
            dayNamesHtml = String.Format("<tr>{0}</tr>", dayNamesHtml);
            table.InnerHtml += dayNamesHtml;

            StringBuilder sb = new StringBuilder("<tr>");
            for (int a = 1; a < dayOfWeekFirst; a++)
            {
                sb.Append("<td></td>");
            }
            for (int i = 1; i <= daysInCurrentMonth; i++)
            {
                DateTime renderedDay = new DateTime(firstDay.Year, firstDay.Month, i);

                Schedule schedule = schedules.Where(x => x.StartTime.Day.Equals(renderedDay.Day) &&
                                     x.StartTime.Month.Equals(renderedDay.Month) &&
                                     x.StartTime.Year.Equals(renderedDay.Year)).FirstOrDefault();


                String lnk = i.ToString();
                if (schedule != null)
                {
                    lnk = String.Format("<a href=\"{0}/?employeeId={1}&date={2}\">{3}</a>", "/Schedules/Details", employeeId, schedule.StartTime.ToShortDateString(), i);
                }

                String cls = "";
                if (renderedDay.DayOfWeek == DayOfWeek.Sunday ||
                    renderedDay.DayOfWeek == DayOfWeek.Saturday) {
                    cls = "calendar-holiday";
                }

                DateTime now = DateTime.Now;
                if (now.Day.Equals(renderedDay.Day) &&
                    now.Month.Equals(renderedDay.Month) &&
                    now.Year.Equals(renderedDay.Year)) {
                    cls = "calendar-today";
                }

                if (String.IsNullOrEmpty(cls))
                    sb.AppendFormat("<td>{0}</td>", lnk);
                else
                    sb.AppendFormat("<td class=\"{0}\">{1}</td>", cls, lnk);

                if (renderedDay.DayOfWeek == DayOfWeek.Sunday)
                    sb.AppendFormat("</tr><tr>");

            }
            for (int a = 1; a < dayOfWeekLast; a++)
            {
                sb.Append("<td></td>");
            }
            sb.Append("</tr>");
            table.InnerHtml += sb.ToString();
            return MvcHtmlString.Create(table.ToString());
        } 
        #endregion

        #region CyclicTaskCalendar
        public static MvcHtmlString CyclicTaskCalendar(this HtmlHelper helper, int employeeId, IEnumerable<MobileSales.Model.Tasks.CyclicTask> tasks,
                int year = -1, int month = -1)
        {
            if (year < 0 || month < 0)
            {
                year = DateTime.Now.Year;
                month = DateTime.Now.Month;
            }


            DateTime firstDay = new DateTime(year, month, 1);
            int daysInCurrentMonth = DateTime.DaysInMonth(firstDay.Year, firstDay.Month);
            DateTime lastDay = new DateTime(year, month, daysInCurrentMonth);
            // Sunday casted to int gives 0 but that will not work for us, we need 7 to be able to calculate number of empty cells correctly
            int dayOfWeekFirst = ((int)firstDay.DayOfWeek > 0) ? (int)firstDay.DayOfWeek : 7;
            int dayOfWeekLast = ((int)lastDay.DayOfWeek > 0) ? (int)lastDay.DayOfWeek : 7;
            dayOfWeekLast = 7 - dayOfWeekLast;

            String[] dayNames = new String[] { Strings.Mon, Strings.Tue, Strings.Wed, Strings.Thu, Strings.Fri, Strings.Sat, Strings.Sun };
            String[] monthNames = new String[] { Strings.January, Strings.February, Strings.March, Strings.April, Strings.May, Strings.June, 
                                                 Strings.July, Strings.August, Strings.September, Strings.October, Strings.November, Strings.December };



            String prev = String.Format("<a href=\"{0}?employeeId={1}&date={2}\">&laquo;</a>",
                                        "/CyclicTasks/",
                                        employeeId,
                                        firstDay.AddMonths(-1).ToShortDateString());

            String next = String.Format("<a href=\"{0}?employeeId={1}&date={2}\">&nbsp;&raquo;&nbsp;</a>",
                                        "/CyclicTasks/",
                                        employeeId,
                                        firstDay.AddMonths(1).ToShortDateString());



            TagBuilder table = new TagBuilder("table");
            table.MergeAttribute("class", "calendar-table");
            table.AddCssClass("calendar");
            table.InnerHtml = "<thead>" +
                              "      <tr>" +
                              "         <th>" + prev + "</th>" +
                              "         <th colspan=\"5\">" + String.Format("{0} {1}", monthNames[month - 1], year) + "</th>" +
                              "         <th>" + next + "</th>" +
                              "      </tr>" +
                              "</thead>";

            String dayNamesHtml = "";
            foreach (var dayName in dayNames)
            {
                dayNamesHtml += String.Format("<td>{0}</td>", dayName);
            }
            dayNamesHtml = String.Format("<tr>{0}</tr>", dayNamesHtml);
            table.InnerHtml += dayNamesHtml;

            StringBuilder sb = new StringBuilder("<tr>");
            for (int a = 1; a < dayOfWeekFirst; a++)
            {
                sb.Append("<td></td>");
            }
            for (int i = 1; i <= daysInCurrentMonth; i++)
            {
                DateTime renderedDay = new DateTime(firstDay.Year, firstDay.Month, i);

                List<CyclicTask> fitTasks = new List<CyclicTask>();
                foreach (var tsk in tasks)
                {
                    TimeSpan span = tsk.StartTime - new DateTime(renderedDay.Year, renderedDay.Month, renderedDay.Day,
                                                                 tsk.StartTime.Hour, tsk.StartTime.Minute, tsk.StartTime.Second);
                    int diff = Math.Abs(span.Days) % tsk.TaskInterval;
                    if (diff == 0)
                    {
                        fitTasks.Add(tsk);
                    }
                }

                String lnk = String.Format("{0}<br/>", i);
                foreach (var tsk in fitTasks)
                {
                    lnk += String.Format("<a href=\"{0}/{1}\">#{2}</a><br/>", "/CyclicTasks/Details", tsk.Id, tsk.Id);
                }

                String cls = "";
                if (renderedDay.DayOfWeek == DayOfWeek.Sunday ||
                    renderedDay.DayOfWeek == DayOfWeek.Saturday)
                {
                    cls = "calendar-holiday";
                }

                DateTime now = DateTime.Now;
                if (now.Day.Equals(renderedDay.Day) &&
                    now.Month.Equals(renderedDay.Month) &&
                    now.Year.Equals(renderedDay.Year))
                {
                    cls = "calendar-today";
                }

                if (String.IsNullOrEmpty(cls))
                    sb.AppendFormat("<td>{0}</td>", lnk);
                else
                    sb.AppendFormat("<td class=\"{0}\">{1}</td>", cls, lnk);

                if (renderedDay.DayOfWeek == DayOfWeek.Sunday)
                    sb.AppendFormat("</tr><tr>");

            }
            for (int a = 1; a < dayOfWeekLast; a++)
            {
                sb.Append("<td></td>");
            }
            sb.Append("</tr>");
            table.InnerHtml += sb.ToString();
            return MvcHtmlString.Create(table.ToString());
        }  
        #endregion

        #region TaskTypeSelect
        public static MvcHtmlString TaskTypeSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<TaskType> types = null;
            try
            {
                TaskServiceClient taskService = new TaskServiceClient();
                taskService.AddValidationToken(Token(helper));
                types = taskService.GetTaskTypeList();
                taskService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (types != null)
            {
                foreach (var status in types)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", status.Id.ToString());
                    if (selectedValue.HasValue && status.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = status.Name.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());

        }  
        #endregion

        #region TaskStatusSelect
        public static MvcHtmlString TaskStatusSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<TaskStatus> statuses = null;
            try
            {
                TaskServiceClient taskService = new TaskServiceClient();
                taskService.AddValidationToken(Token(helper));
                statuses = taskService.GetTaskStatusList();
                taskService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (statuses != null)
            {
                foreach (var status in statuses)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", status.Id.ToString());
                    if (selectedValue.HasValue && status.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = status.Name.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());

        }
        #endregion

        #region DocumentDirectionSelect
        public static MvcHtmlString DocumentDirectionSelect(this HtmlHelper helper, string fieldName, string selectedValue = null)
        {
            string[] availableValues = Enum.GetNames(typeof(Model.Documents.DocumentDirection));
            Dictionary<string, string> localizedValues = new Dictionary<string, string>();
            localizedValues.Add(Model.Documents.DocumentDirection.Incoming.ToString(), Strings.Incoming);
            localizedValues.Add(Model.Documents.DocumentDirection.Outcoming.ToString(), Strings.Outcoming);
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);


            foreach (var val in availableValues)
            {
                TagBuilder option = new TagBuilder("option");
                option.MergeAttribute("value", val);
                if (string.IsNullOrEmpty(selectedValue) && val.Equals(selectedValue))
                {
                    option.MergeAttribute("selected", "selected");
                }
                option.InnerHtml = localizedValues[val];
                select.InnerHtml += option.ToString();
            }
            return MvcHtmlString.Create(select.ToString());
        } 
        #endregion

        #region PaymentMethodSelect
        public static MvcHtmlString PaymentMethodSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<PaymentMethod> meths = null;
            try
            {
                DocumentServiceClient documentService = new DocumentServiceClient();
                documentService.AddValidationToken(Token(helper));
                meths = documentService.GetPaymentMethodList();
                documentService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (meths != null)
            {
                foreach (var m in meths)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", m.Id.ToString());
                    if (selectedValue.HasValue && m.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = m.Name.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());

        }
        #endregion

        #region DocumentTypeSelect
        public static MvcHtmlString DocumentTypeSelect(this HtmlHelper helper, string fieldName, int? selectedValue = null)
        {
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", fieldName);
            IEnumerable<DocumentType> types = null;
            try
            {
                DocumentServiceClient documentService = new DocumentServiceClient();
                documentService.AddValidationToken(Token(helper));
                types = documentService.GetDocumentTypeList();
                documentService.Close();
            }
            catch (Exception ex)
            {
                CLogger.LogDebug(ex);
                return MvcHtmlString.Empty;
            }

            if (types != null)
            {
                foreach (var t in types)
                {
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", t.Id.ToString());
                    if (selectedValue.HasValue && t.Id.Equals(selectedValue.Value))
                    {
                        option.MergeAttribute("selected", "selected");
                    }
                    option.InnerHtml = t.Name.ToString();
                    select.InnerHtml += option.ToString();
                }
            }
            return MvcHtmlString.Create(select.ToString());

        }
        #endregion

        #region DatePickerLocalization
        public static MvcHtmlString DatePickerLocalization(this HtmlHelper helper)
        {
            if (Thread.CurrentThread.CurrentUICulture.Equals(new CultureInfo("pl"))) 
            {
                return MvcHtmlString.Create(string.Format("<script src=\"{0}\" type=\"text/javascript\"></script>","/Scripts/jquery.ui.datepicker-pl.js")); 
            }
            return MvcHtmlString.Empty;
        }
        #endregion

        #region DataTablesLocalization
        public static MvcHtmlString DataTablesLocalization(this HtmlHelper helper)
        {
            string lang = Thread.CurrentThread.CurrentUICulture.Name.Substring(0, 2).ToLower();
            if (lang == "en") lang = "";
            else lang += ".";

            return MvcHtmlString.Create(string.Format("<script src=\"/Scripts/jquery.dataTables.{0}min.js\" type=\"text/javascript\"></script>", lang));

        } 
        #endregion

        #region ParseDictionary
        public static MvcHtmlString ParseDictionary(this HtmlHelper helper, string dict)
        {
            StringBuilder sb = new StringBuilder();
            string[] kv = dict.Split(';');
            if (kv != null)
            {
                sb.Append("<ul>");
                bool first = true;
                foreach(var keyval in kv) 
                {
                    string[] key = keyval.Split('=');
                    if (key.Length > 0)
                    {
                        if (first)
                        {
                            sb.AppendFormat("<li><b>{0}</b></li>", key[0]);
                            first = false;
                        }
                        else
                            sb.AppendFormat("<li>{0}</li>", key[0]);
                    }
                }
                sb.Append("</ul>");
            }
            return MvcHtmlString.Create(sb.ToString());
        }
        #endregion

        #region PercentageFormat
        public static MvcHtmlString PercentageFormat(this HtmlHelper helper, double value)
        {
            return MvcHtmlString.Create(String.Format("{0} %", (int)(value * 100)));
        } 
        #endregion

        #region LanguageSelect
        public static MvcHtmlString LanguageSelect(this HtmlHelper helper, string controller, string action)
        {
            string returnUrl = string.Format("/{0}/{1}", controller, action);
            TagBuilder select = new TagBuilder("select");
            select.MergeAttribute("name", "lang");
            select.MergeAttribute("class", "lang-select");
            select.MergeAttribute("onchange", "window.open(this.options[this.selectedIndex].value,'_top')");

            String[] languages = Settings.Default.AvailableLanguages.Split(';');
            StringBuilder sb = new StringBuilder();
            String currentCultureSymb = CultureHelper.GetCurrentCulture().Name;
            if (languages != null)
            {
                foreach (var lang in languages)
                {
                    CultureInfo culture = new CultureInfo(lang);
                    TagBuilder option = new TagBuilder("option");
                    option.MergeAttribute("value", string.Format("/{0}/SetLanguage?lang={1}&returnPath={2}", controller, lang, returnUrl));
                    if (lang == currentCultureSymb)
                        option.MergeAttribute("selected", "selected");

                    string cultureNativeName = culture.NativeName.Split(' ')[0];
                    cultureNativeName = char.ToUpper(cultureNativeName[0]) + cultureNativeName.Substring(1);

                    option.InnerHtml = cultureNativeName;
                    sb.Append(option.ToString());
                }
            }
            select.InnerHtml = sb.ToString();
            return MvcHtmlString.Create(select.ToString());
        } 
        #endregion



    }
}